#include "thread_pool.hpp"
#include "spin_lock.hpp"





void ThreadPool::WorkerThread(ThreadPool *master){
    while(master->alive == 1){
        Task *task = master->getTask();
        if (task != nullptr){
            task->run();
            master->pending_task_count--;//调用Task的run函数
        }else{
            std::this_thread::yield();
        }
    }
}

ThreadPool::ThreadPool(size_t thread_count){
    alive = 1;
    pending_task_count = 0;
    if(thread_count==0){
        //中文：std::thread::hardware_concurrency()返回可并发执行的线程数
        thread_count = std::thread::hardware_concurrency();
    }
    //向 threads 向量中添加一个新的 std::thread 对象。这个新线程对象将执行 ThreadPool::WorkerThread 函数，并且可以访问当前 ThreadPool 对象的成员变量和成员函数
    for(size_t i = 0; i< thread_count;i++){
        threads.push_back(std::thread(ThreadPool::WorkerThread,this));
    }
}


ThreadPool::~ThreadPool(){
    wait();
    //
    alive = 0;
    
    //auto &thread 表示循环变量 thread 是一个对向量中每个 std::thread 对象的引用
    for (auto &thread: threads){
        //join 函数的作用是阻塞当前线程，直到被调用的线程完成执行
        thread.join();
    }
    //清空线程池
    threads.clear();
}
class ParallelForTask: public Task {
public:
    ParallelForTask(size_t x, size_t y, const std::function<void(size_t, size_t)> &lambda)
        : x(x), y(y), lambda(lambda) {}
    void run() override {
        lambda(x, y);
    }
private:
    size_t x, y;
    std::function<void(size_t, size_t)> lambda;

    
};

void ThreadPool::parallelFor( size_t width, size_t height, const std::function<void(size_t, size_t)> &lambda){
    Guard guard(spin_lock);
    for (size_t x=0; x<width; x++){
        for (size_t y=0; y<height; y++){
            pending_task_count++;
            tasks.push(new ParallelForTask{x, y, lambda}); 
        }
    }
};

void ThreadPool::wait() const{
    while(pending_task_count > 0){
        std::this_thread::yield();
    }
}

void ThreadPool::addTask(Task *task){
    Guard guard(spin_lock);
    pending_task_count++;
    tasks.push(task);
}

Task *ThreadPool::getTask(){
    Guard guard(spin_lock);
    if(tasks.empty()) {
        return nullptr;
    }
    //取出tasks中的第一个元素
    Task *task = tasks.front();
    //删除tasks中的第一个元素 确保只调用一次
    tasks.pop();
    //返回取出的元素
    return task;
}